package app.controllers.api.member;

import app.Const;
import app.base.AuthController;
import app.constant.AccountStatus;
import app.dtos.AccountDto;
import app.kit.AuthRedisKit;
import app.kit.CommonKit;
import app.models.member.Account;
import app.models.member.AccountAmount;
import app.models.member.BankCard;
import app.models.member.Member;
import app.services.auth.AuthInterceptor;
import app.services.auth.AuthParam;
import bank.BankService;
import bank.resp.BindUserRspDto;
import com.google.common.base.Function;
import com.google.common.base.Optional;
import com.google.common.base.Strings;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Lists;
import com.google.common.collect.Multimaps;
import com.jfinal.aop.Before;
import com.jfinal.ext.interceptor.GET;
import com.jfinal.ext.interceptor.POST;
import com.jfinal.plugin.activerecord.Db;
import com.jfinal.plugin.activerecord.IAtom;
import goja.Validator;
import goja.encry.DigestsKit;
import goja.encry.EncodeKit;
import goja.lang.Lang;
import goja.mvc.AjaxMessage;
import goja.security.goja.SecurityKit;
import org.apache.commons.lang3.RandomStringUtils;
import org.joda.time.DateTime;

import java.sql.SQLException;
import java.util.Collection;
import java.util.List;

import static goja.StringPool.PK_COLUMN;

/**
 * <p>
 * The url member/account Controller.
 * </p>
 *
 * @author sagyf yang
 * @version 1.0
 * @since JDK 1.6
 */
public class AccountController extends AuthController {

    public static final String ELECTRONIC_ACCOUNT_FIELD = "electronic_account";

    public static final Function<AccountAmount, Integer> RECORD_MONTH_GROUPFUNCTION = new Function<AccountAmount, Integer>() {
        @Override
        public Integer apply(AccountAmount input) {
            return input.getNumber("record_month").intValue();
        }
    };

    /**
     * the url /member/account
     */
    public void index() {
        renderNull();
    }


    /**
     * 开通电子账户
     */
    @Before({POST.class, AuthInterceptor.class})
    @AuthParam(auth = true)
    public void open() {
        String username = getPara("username");
        String id_card = getPara("id_card");
        if (!Validator.isIdentityCard(id_card)) {
            renderAjaxFailure("请输入合法的身份证号码！");
            return;
        }
        String phone = getPara("phone");
        if (!CommonKit.isMoible(phone)) {
            renderAjaxFailure("请输入正确的手机号码！");
            return;
        }
        String email = getPara("email");
        if (!Validator.isEmail(email)) {
            renderAjaxFailure("请输入正确的电子邮箱地址！");
            return;
        }

        final Member member = getAttr(AuthInterceptor.ATTR_MEMBER);
        if (!Strings.isNullOrEmpty(member.getStr(ELECTRONIC_ACCOUNT_FIELD))) {
            renderAjaxFailure("你已经开通了电子账户，无法重复开通!");
            return;
        }
        final String ele_code = RandomStringUtils.randomNumeric(18);

        member.set("real_name", username);
        member.set("cart_no", id_card);
        member.set("email", email);
        // 测试电子账号，TODO 需要更换为接口并取得电子账号ID
        member.set(ELECTRONIC_ACCOUNT_FIELD, ele_code);

        final Account account = Account.dao.findbyMember(member.getNumber(PK_COLUMN).intValue());
        account.set(Const.FIELD_AMOUNT, 0);
        account.set("available", 0);
        account.set("freeze", 0);
        account.set(Const.FIELD_STATUS, AccountStatus.NORMAL);
        //生成随即号，todo 联调
        account.set(ELECTRONIC_ACCOUNT_FIELD, ele_code);

        final boolean tx = Db.tx(new IAtom() {
            @Override
            public boolean run() throws SQLException {
                return account.update() && member.update();
            }
        });
        if (tx) {
            renderAjaxSuccess(account);
        } else {
            renderAjaxFailure("开通电子账户失败，请稍后重试");
        }


    }


    /**
     * 绑定电子账户
     */
    @Before({POST.class, AuthInterceptor.class})
    @AuthParam(auth = true)
    public void electronicbind() {
        // 真实姓名
        String realName = getPara("realname");
        // 身份证
        String id_card = getPara("id_card");
        // 电子账户
        String electronic = getPara("electronic");
        if (Strings.isNullOrEmpty(realName)) {
            renderAjaxFailure("请输入您的真实姓名！");
            return;
        }
        if (Strings.isNullOrEmpty(electronic)) {
            renderAjaxFailure("请输入您的电子账号，如果您还没有电子账户，请参考下方提示开通电子账号！");
            return;
        }
        if (!Validator.isIdentityCard(id_card)) {
            renderAjaxFailure("请输入合法的身份证号码！");
            return;
        }


        DateTime now = DateTime.now();

        final Member member = getMember();

         String code = member.getStr(Const.FIELD_CODE);
        final Optional<BindUserRspDto> bindUserResp = BankService.me.
                bindUser(now, now, code, id_card, realName, member.getStr("phone"), electronic);
        if (bindUserResp.isPresent() ) {
            final BindUserRspDto userRespDto = bindUserResp.get();
            if(userRespDto.isSuccess()){
                // 绑定成功的处理

                member.set("real_name", realName);
                member.set("cart_no", id_card);
                member.set("bind_bank_card", Const.YES);
                member.set(ELECTRONIC_ACCOUNT_FIELD, electronic);

                final Account account = Account.dao.findbyMember(member.getNumber(PK_COLUMN).intValue());
                account.set(Const.FIELD_AMOUNT, 0);
                account.set("available", 0);
                account.set("freeze", 0);
                account.set(Const.FIELD_STATUS, AccountStatus.NORMAL);
                account.set(ELECTRONIC_ACCOUNT_FIELD, electronic);

                final boolean tx = Db.tx(new IAtom() {
                    @Override
                    public boolean run() throws SQLException {
                        return account.update() && member.update();
                    }
                });
                if (tx) {
                    renderAjaxSuccess(account);
                } else {
                    renderAjaxFailure("绑定电子账户失败，请稍后重试");
                }
            } else {
                renderAjaxFailure(userRespDto.getRespMsg());
            }

        } else {
            renderAjaxFailure();
        }


    }


    /**
     * 绑定银行卡
     */
    @Before({POST.class, AuthInterceptor.class})
    @AuthParam(auth = true)
    public void bindcard() {
        String card_no = getPara("card_no");
        String name = getPara(Const.FIELD_NAME);
        String bank = getPara("bank");
        String id_card = getPara("id_card");
        String phone = getPara("phone");
        if (!Validator.isIdentityCard(id_card)) {
            renderAjaxFailure("请输入合法的身份证号码！");
            return;
        }
        if (!CommonKit.isMoible(phone)) {
            renderAjaxFailure("请输入正确的手机号码！");
            return;
        }
        final Member member = getAttr(AuthInterceptor.ATTR_MEMBER);
        final BankCard bankCard = new BankCard();
        final int memberId = getAttrForInt(AuthInterceptor.ATTR_MEMBER_PK);
        bankCard.set(Const.FIELD_MEMBER, memberId);
        bankCard.set("bank", bank);
        bankCard.set("bank_card", card_no);
        bankCard.set("cardholder", name);
        // TODO 这种银行类型等字段需要后续通过接口来触发确定
        bankCard.set("card_type", "储蓄卡");
        bankCard.set("verify_amount", 0.00);
        bankCard.set("bind_time", DateTime.now());

        // 绑定银行卡
        member.set("bind_bank_card", Const.YES);
        final boolean tx = Db.tx(new IAtom() {
            @Override
            public boolean run() throws SQLException {
                return bankCard.save() && member.update();
            }
        });
        if (tx) {
            // 更新缓存中的会员信息
            AuthRedisKit.setMember(member, memberId);
            renderAjaxSuccess(bankCard);
        } else {
            renderAjaxFailure("绑定银行卡失败，请稍后重试");
        }
    }

    /**
     * 我的银行卡
     */
    @Before({GET.class, AuthInterceptor.class})
    @AuthParam(auth = true)
    public void cards() {

        final int memberId = getAttrForInt(AuthInterceptor.ATTR_MEMBER_PK);

        List<BankCard> bankCards = BankCard.dao.findByMember(memberId);
        if (Lang.isEmpty(bankCards)) {
            renderJson(AjaxMessage.nodata());
        } else {
            renderAjaxSuccess(bankCards);
        }
    }


    /**
     * 设置交易密码
     */
    @Before({POST.class, AuthInterceptor.class})
    @AuthParam(auth = true)
    public void password() {
        String password = getPara("password");
        if (!Strings.isNullOrEmpty(password)) {
            final int memberId = getAttrForInt(AuthInterceptor.ATTR_MEMBER_PK);

            final Account account = Account.dao.findbyMember(memberId);

            // 设置交易密码
            byte[] salt = DigestsKit.generateSalt(EncodeKit.SALT_SIZE);
            account.set("trade_pwd_salt", EncodeKit.encodeHex(salt));
            byte[] hashPassword = DigestsKit.sha1(password.getBytes(), salt, EncodeKit.HASH_INTERATIONS);
            account.set("trade_pwd", EncodeKit.encodeHex(hashPassword));

            final Member member = getAttr(AuthInterceptor.ATTR_MEMBER);
            // 设置交易密码OK
            member.set("trade_password_flag", true);

            final boolean ok = Db.tx(new IAtom() {
                @Override
                public boolean run() throws SQLException {
                    return account.update() && member.update();
                }
            });

            if (ok) {
                AuthRedisKit.setMember(member, memberId);
                renderAjaxSuccess(member);
                return;
            }
        }
        renderAjaxFailure();
    }


    /**
     * 验证交易密码
     */
    @Before({POST.class, AuthInterceptor.class})
    @AuthParam(auth = true)
    public void checkpassword() {
        String password = getPara("password");
        if (!Strings.isNullOrEmpty(password)) {
            final int memberId = getAttrForInt(AuthInterceptor.ATTR_MEMBER_PK);
            final Account account = Account.dao.findbyMember(memberId);

            boolean matcher = SecurityKit.checkPassword(account.getStr("trade_pwd_salt"),
                    account.getStr("trade_pwd"),
                    password);
            if (matcher) {
                renderAjaxSuccess();
                return;
            }
        }
        renderAjaxFailure();
    }

    /**
     * 账户纪录
     */
    @Before({GET.class, AuthInterceptor.class})
    @AuthParam(auth = true)
    public void records() {

        final int memberId = getAttrForInt(AuthInterceptor.ATTR_MEMBER_PK);
        // 页码
        int page = getParaToInt(0, 1);

        List<AccountAmount> accountAmounts = AccountAmount.dao.findByRecord(page, memberId);

        final ImmutableMap<Integer, Collection<AccountAmount>> month_datas =
                Multimaps.index(accountAmounts, RECORD_MONTH_GROUPFUNCTION).asMap();
        List<AccountDto> accountDtos = Lists.newArrayListWithCapacity(month_datas.size());

        for (Integer month : month_datas.keySet()) {
            accountDtos.add(new AccountDto(month, month_datas.get(month)));
        }
        renderAjaxSuccess(accountDtos);

    }
}